package main;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import regression.ProblemRegression;

public class ItsChooser {

	private Its itsList[];

	public Its[] getItsList() {
		return itsList;
	}

	private Map<String, Double> goals;
	private ArrayList<Its> pickedIts;

	public ItsChooser(Its[] itsList) {
		this.itsList = itsList;
	}

	public ResultSet getResults(Map<String, Double> goals, int year) {
		itsList = DataConnection.readData();
		this.goals = regression(goals, year); // goals;
		pickedIts = pickIts();
//		printIts();
		ResultSet results = new ResultSet(getMapping());

		Map<String, Double> potential = calcPotential();
		System.out.println("Its are capable: " + potential);
		if (!checkPotential(potential)) { // if potential below goals
			results.setPolicy(true);
			// resultSet contains all pickedIts's
			int[] allPicked = new int[pickedIts.size()];
			for(int i=0; i<allPicked.length; i++)
				allPicked[i] = i+1;
			results.addItsSet(allPicked, potential);
			return results;
		}
		
		return BranchAndBound.genereteResults(pickedIts, goals, results);
		// return bruteForce(results);
	}

	private Map<String, Double> regression(Map<String, Double> goals2, int year) {				
		Date goalDate = intToDate(year);
		double percents = 0.0;
		
		Map<String, Double> newGoals = new HashMap<String, Double>(goals2);
			for (Map.Entry<String, Double> goal : newGoals.entrySet()) {
				percents = regr2percents(goal.getKey(), goal.getValue(), goalDate);
				goal.setValue(percents);
			}
		
		return newGoals;
	}

	private double regr2percents(String probName, Double goalPercent, Date goalDate) {
		Date today = new Date();
		ProblemRegression pre = null;
		double now, future, result = 0.0;
		
		try {
			pre = new ProblemRegression(probName);
			now = pre.getNumberFor(today);
			future = pre.getNumberFor(goalDate);
			result = (now*goalPercent)/future;
			if(result > 1.0)
				result = 1.0;
		} catch (Throwable e) {
			System.out.println(e.getMessage() + e.getStackTrace());
		}
		
		return result;
	}

	private boolean checkPotential(Map<String, Double> potential) {
		for (Map.Entry<String, Double> goal : goals.entrySet()) {
			if (potential.get(goal.getKey()) < goal.getValue())
				return false;
		}
		return true;
	}

	private int[] getMapping() {
		int pickedSize = pickedIts.size();
		int mapping[] = new int[pickedSize];
		int i = 0;
		for (Its pIts : pickedIts) {
			for (int j = 0; j < itsList.length; j++) {
				if (itsList[j].equals(pIts)) {
					mapping[i++] = j;
					break;
				}
			}
		}
		return mapping;
	}

	private ResultSet bruteForce(ResultSet results) {
		SubsetGenerator sg;

		int pickedSize = pickedIts.size();
		for (int i = 1; i <= pickedSize; i++) {
			sg = new SubsetGenerator(pickedSize, i);
			while (sg.hasNext()) {
				int sub[] = sg.getNext();
				Map<String, Double> performance = calcPerformance(sub);
				if (checkPotential(performance)) {
					// System.out.println("subset: " + printIntTab(sub));
					results.addItsSet(sub, performance);
				}
			}
		}

		return results;
	}

	private ArrayList<Its> pickIts() {
		ArrayList<Its> itsSet = new ArrayList<Its>();
		for (String problem : goals.keySet())
			for (Its it : itsList) {
				if (it.getProblemPerf(problem) > 0.0) {
					if (!itsSet.contains(it))
						itsSet.add(it);
				}
			}
		return new ArrayList<Its>(itsSet);
	}

	public void printIts() {
		System.out.println("Picked ITSs:");
		for (Its its : pickedIts)
			System.out.println(its.getName());
	}

	public Map<String, Double> calcPotential() {
		Map<String, Double> potential = new HashMap<String, Double>();
		for (String problem : goals.keySet()) {
			double sum = 0.0;
			for (Its its : pickedIts) {
				sum += its.getProblemPerf(problem);
			}
			potential.put(problem, sum);
		}
		return potential;
	}

	public Map<String, Double> calcPerformance(int sub[]) {
		Map<String, Double> potential = new HashMap<String, Double>();
		for (String problem : goals.keySet()) {
			double sum = 0.0;
			for (int i : sub) {
				sum += pickedIts.get(i - 1).getProblemPerf(problem);
			}
			potential.put(problem, sum);
		}
		return potential;
	}

	public Date intToDate(int year) {
		Calendar cal = Calendar.getInstance();
		cal.set(year, 1, 1);
		Date date = cal.getTime();
		return date;
	}

	/**
	 * Method takes ITS name and gives back ITS.
	 * 
	 * @param itsName
	 *            ITS name.
	 * @return ITS for given name.
	 */
	public Its getIts(String itsName) {
		for (Its its : this.itsList)
			if (its.getName().equals(itsName))
				return its;

		return null;
	}
}